//File:	E_Render.cpp
#include "E_Render.h"
#include <GL\glfw.h>
#include <GL\glew.h>
#include "MatrixMath.h"
#include "E_Resource.h"
#include "Utility.h"

#include <glm\glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
// glm::value_ptr
#include <glm/gtc/type_ptr.hpp>



// |------- class Render -------|
GLuint Render::m_CurrentShader = 0;
Mat4 Render::m_ViewMatrix;
Mat4 Render::m_ProjectionMatrix;

Render::Render(void)
{
	m_ViewMatrix.Identity();
	m_ProjectionMatrix.Identity();
}
Render::~Render(void)
{
}

void Render::Window_Begin()
{
	if (!glfwInit())
	{
		Utility::Log("Render::Window_Begin() - GLFW: Failed to initialize.\n");
		Render::Window_End();
		return;
	}


	glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 1);
	glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 1);
	//glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);

	//glfwOpenWindowHint(GLFW_FSAA_SAMPLES,4);
	//glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//glfwOpenWindowHint(GLFW_OPENGL_FORWARD_COMPAT,GL_TRUE);
	//glfwDisable( GLFW_AUTO_POLL_EVENTS );

	if( !glfwOpenWindow( 500,500, 0,0,0,0,0,0, GLFW_WINDOW ) )
		glfwTerminate();

	glewExperimental=GL_TRUE;
	GLenum GLEW_Error = glewInit(); 

	if (GLEW_Error != GLEW_OK) 
	{
		Utility::Log("Render::Window_Begin() - GLEW: Failed to initialize, error log follows:\n");
		Utility::Log((char*)glewGetErrorString(GLEW_Error));
		Render::Window_End();
		return;
	}

	Utility::Log("Render: OpenGL version: "+(std::string)(char*)glGetString(GL_VERSION));

	glEnable(GL_TEXTURE_2D);
	glShadeModel(GL_SMOOTH);

	glClearDepth(1.0f);
	glClearColor(0.f, 0.5f, 0.7f, 0.f);
	glDepthMask(GL_TRUE);
	glEnable(GL_DEPTH_TEST);        
	glDepthFunc(GL_LEQUAL);                       
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);         

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(90.f, 1.f, 1.f, 500.f);
}
void Render::Window_End()
{
	glfwTerminate();
	Utility::Log("Render: OpenGL Context terminated.\n");
}

void Render::UseShader(GLuint Shader)
{
	if (Shader != m_CurrentShader)
	{
		m_CurrentShader = Shader;
		glUseProgram(Shader);
	}
}



void Render::PreDraw()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	//glMatrixMode(GL_MODELVIEW);
	//glLoadIdentity();

	GLuint Shader = Resource::LoadShader_Program("Shader.Vertex","Shader.Fragment");
	UseShader(Shader);
	GLuint LocationMVP = glGetUniformLocation(Shader, "MVP");




	/*
	Mat4 Proj;
	Proj.Perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.f);

	Mat4 V;
	Mat4 M;
	V.Identity();
	M.Identity();
	Mat4 MVP = Proj * V * M;

	glUniformMatrix4fv(LocationMVP, 1,GL_FALSE,MVP.SetMat16());
	*/

	
	glm::vec3 Rotate;
	Rotate.x = 0; Rotate.y = 0; Rotate.z = 0;

	glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.f);
	glm::mat4 ViewTranslate = glm::translate( glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -5));
	glm::mat4 ViewRotateX = glm::rotate(ViewTranslate,Rotate.y, glm::vec3(-1.0f, 0.0f, 0.0f));

	glm::mat4 View = glm::rotate(ViewRotateX,Rotate.x, glm::vec3(0.0f, 1.0f, 0.0f));
	glm::mat4 Model = glm::scale(glm::mat4(1.0f), glm::vec3(0.5f));
	glm::mat4 MVP = Projection * View * Model;


	glUniformMatrix4fv(LocationMVP, 1,GL_FALSE,glm::value_ptr(MVP) );
	
}
void Render::Draw()
{
	PreDraw();

	/*
	for(auto it = Resource::DrawList.begin(); it != Resource::DrawList.end();it++)
	{
	DrawModel(it->m_Model);
	}
	*/

	glColor3f(0.5f,0.5f,1.0f);            
	glBegin(GL_QUADS);                 
	glVertex3f(-1.0f, 1.0f, 0.0f);        
	glVertex3f( 1.0f, 1.0f, 0.0f);         
	glVertex3f( 1.0f,-1.0f, 0.0f);          
	glVertex3f(-1.0f,-1.0f, 0.0f);          
	glEnd();               
	


	glfwSwapBuffers();



}

void Render::DrawModel(Model *_Model)
{
	if (_Model != NULL)
	{
		//GLuint LocationMVP = glGetUniformLocation(S.m_Program, "MVP");
		//mat4 Standard = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 1000.f) * glm::translate(glm::mat4(1.0f),glm::vec3(0.0f, 0.0f, -40.0f));

		//mat4 Standard = Cam.m_Matrix;

		//Standard *= GEnt.m_Matrix;
		//glUniformMatrix4fv(LocationMVP, 1,GL_FALSE,glm::value_ptr(Standard));


		for (auto it = _Model->m_Mesh.begin();it != _Model->m_Mesh.end();it++)
		{
			DrawMesh(&(*it));
		}
	}
}
void Render::DrawMesh(Mesh *_Mesh)
{
	glEnableClientState(GL_VERTEX_ARRAY);
	glVertexPointer(3, sizeof(SimpleVertex), 0, &_Mesh->m_Interleaved[0].x);

	glDrawArrays(GL_TRIANGLES,0,6);
	glDisableClientState(GL_VERTEX_ARRAY);
}
